
#include <BSerialPort>
#include "member_BSerialPort.h"

using namespace BWE;

#define member					(*(member_BSerialPort*)_ptr)
#define member_allocate()		_ptr = new member_BSerialPort(this)
#define member_release()		delete (member_BSerialPort*)_ptr

BSerialPort::BSerialPort()
{
	member_allocate();
}
BSerialPort::~BSerialPort()
{
	close();
	member_release();
}

void BSerialPort::setPortName(const BString& portName)
{
	if (member.portName != portName)
	{
		member.portName = portName;
		close();
	}
}
const BString& BSerialPort::portName() const
{
	return member.portName;
}

bool BSerialPort::setBaudRate(BaudRate baudRate)
{
	if (member.baudRate != baudRate)
	{
		member.baudRate = baudRate;
		member.freshComState();
		return true;
	}
	return false;
}
BSerialPort::BaudRate BSerialPort::baudRate() const
{
	return member.baudRate;
}

bool BSerialPort::setDataBits(DataBits dataBits)
{
	if (member.dataBits != dataBits)
	{
		member.dataBits = dataBits;
		member.freshComState();
	}
	return true;
}
BSerialPort::DataBits BSerialPort::dataBits() const
{
	return member.dataBits;
}

bool BSerialPort::setDirection(Direction direction)
{
	if (member.direction != direction)
	{
		member.direction = direction;
		member.freshComState();
	}
	return true;
}
BSerialPort::Direction BSerialPort::direction() const
{
	return member.direction;
}

bool BSerialPort::setFlowControl(FlowControl flowControl)
{
	if (member.flowControl != flowControl)
	{
		member.flowControl = flowControl;
		member.freshComState();
	}
	return true;
}
BSerialPort::FlowControl BSerialPort::flowControl() const
{
	return member.flowControl;
}

bool BSerialPort::setParity(Parity parity)
{
	if (member.parity != parity)
	{
		member.parity = parity;
		member.freshComState();
	}
	return true;
}
BSerialPort::Parity BSerialPort::parity() const
{
	return member.parity;
}

bool BSerialPort::setStopBits(StopBits stopBits)
{
	if (member.stopBits != stopBits)
	{
		member.stopBits = stopBits;
		member.freshComState();
	}
	return true;
}
BSerialPort::StopBits BSerialPort::stopBits() const
{
	return member.stopBits;
}

bool BSerialPort::open(Mode mode)
{
	close();

	BString name("\\\\.\\");
	name += member.portName;
	DWORD access = 0;
	if (mode == ModeRead)
		access = GENERIC_READ;
	if (mode == ModeWrite)
		access = GENERIC_WRITE;
	if (mode == ModeReadWrite)
		access = GENERIC_READ | GENERIC_WRITE;
	
	DWORD share = 0;
	DWORD flags = FILE_ATTRIBUTE_NORMAL;
	member.hcom = CreateFile(name.cstr(), access, share, 0, OPEN_EXISTING, flags, 0);
	if (member.hcom == INVALID_HANDLE_VALUE)
	{
		member.checkError();
		return false;
	}
	HANDLE hcom = member.hcom;
	member.mode = mode;
	return true;
}
bool BSerialPort::isOpen() const
{
	return member.hcom != INVALID_HANDLE_VALUE;
}
void BSerialPort::close()
{
	if (isOpen())
	{
		CloseHandle(member.hcom);
		member.hcom = INVALID_HANDLE_VALUE;
		member.mode = ModeNone;
	}
}

int BSerialPort::read(char* data, int maxSize)
{
#ifdef _WINDOWS_SYSTEM_
	DWORD readSize = 0;
	OVERLAPPED overlapped;
	BOOL ret = ReadFile(member.hcom, data, maxSize, &readSize, &overlapped);
	if (ret)
		return readSize;
	return -1;
#endif
}
int BSerialPort::read(BByteArray& bytes, int maxSize)
{
	if (maxSize < 0)
		maxSize = bytes.size();
	if (maxSize == 0)
		bytes.clear();
#ifdef _WINDOWS_SYSTEM_
	DWORD readSize = 0;
	BOOL ret = ReadFile(member.hcom, bytes.data(), maxSize, &readSize, 0);// &overlapped);
	if (ret)
		return readSize;
	return -1;
#endif
}

int BSerialPort::write(const void* data, int size)
{
	if (isOpen() && member.mode & ModeWrite)
	{
#ifdef _WINDOWS_SYSTEM_
		DWORD writeSize = 0;
		BOOL ret = WriteFile(member.hcom, data, size, &writeSize, 0);
		if (!ret)
		{
			member.checkError();
			return -1;
		}
		return writeSize;
#endif
	}
	return -1;
}
int BSerialPort::write(const BByteArray& bytes)
{
	if (isOpen() && member.mode & ModeWrite)
	{
#ifdef _WINDOWS_SYSTEM_
		DWORD writeSize = 0;
		BOOL ret = WriteFile(member.hcom, bytes.data(), bytes.size(), &writeSize, 0);
		if (!ret)
		{
			member.checkError();
			return -1;
		}
		return writeSize;
#endif
	}
	return -1;
}
bool BSerialPort::flush()
{
#ifdef _WINDOWS_SYSTEM_
	if (isOpen())
	{
		BOOL ret = FlushFileBuffers(member.hcom);
	}
#endif
	return true;
}
